package com.xunyin.utils.alioss;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.model.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;


/**
 * @类名称 AliyunOSSClientUtil.java
 * @类描述 <pre>上传文件到OSS服务器工具类</pre>
 * @版本 1.00
 * @修改记录
 */
@Slf4j
public class AliyunOSSClientUtil {
    // log日志
    private static final String PROPERTIES_PATH = "/oss/oss.properties";
    // 阿里云API的内或外网域名
    private static String ENDPOINT;
    // 阿里云API的密钥Access Key ID
    private static String ACCESS_KEY_ID;
    // 阿里云API的密钥Access Key Secret
    private static String ACCESS_KEY_SECRET;
    // 阿里云API的bucket名称
    private static String BUCKET_NAME;

    public static String DOMAIN_NAME;

    public static String OOS_URL;

    // 初始化属性
    static {
        PropertiesFileUtil ps = PropertiesFileUtil.getInstance(PROPERTIES_PATH);
        ENDPOINT = ps.get("oss.endpoint");
        ACCESS_KEY_ID = ps.get("oss.access_key_id");
        ACCESS_KEY_SECRET = ps.get("oss.access_key_secret");
        BUCKET_NAME = ps.get("oss.bucket_name");
        DOMAIN_NAME = ps.get("oss.oss_domain_name");
        OOS_URL = ps.get("oos.oss_url");
    }

    /**
     * 得到阿里云OSS的参数，用于直传
     *
     * @return
     * @throws UnsupportedEncodingException
     */
    public static JSONObject getPostObjectPolicy(String dir) throws UnsupportedEncodingException {

        String endpoint = ENDPOINT;
        String accessId = ACCESS_KEY_ID;
        String accessKey = ACCESS_KEY_SECRET;
        String host = DOMAIN_NAME;
        OSSClient client = new OSSClient(endpoint, accessId, accessKey);
        long expireTime = 300;
        long expireEndTime = System.currentTimeMillis() + expireTime * 1000;
        Date expiration = new Date(expireEndTime);
        PolicyConditions policyConds = new PolicyConditions();
        policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000);
        policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);

        String postPolicy = client.generatePostPolicy(expiration, policyConds);
        byte[] binaryData = postPolicy.getBytes("utf-8");
        String encodedPolicy = BinaryUtil.toBase64String(binaryData);
        String postSignature = client.calculatePostSignature(postPolicy);

        //String callBackBody = "{\"callbackUrl\":\"http://oss-demo.aliyuncs.com:23450\",\"callbackHost\":\"oss-demo.aliyuncs.com\",\"callbackBody\":\"filename=${object}&size=${size}&mimeType=${mimeType}\",\"callbackBodyType\":\"application/x-www-form-urlencoded\"}";

        Map<String, String> respMap = new LinkedHashMap<String, String>();
        respMap.put("accessid", accessId);
        respMap.put("policy", encodedPolicy);
        respMap.put("signature", postSignature);
        //respMap.put("expire", formatISO8601Date(expiration));
        respMap.put("dir", dir);
        respMap.put("host", host);
        respMap.put("expire", String.valueOf(expireEndTime / 1000));
        JSONObject ja1 = JSONObject.parseObject(JSON.toJSONString(respMap));

        client.shutdown();

        System.out.println(ja1.toString());
        return ja1;

    }


    /**
     * @param file
     * @param folder
     * @return
     * @方法名称 uploadFileToOSS
     * @功能描述 <pre>上传文件至oss</pre>
     */
    public static OSSObjectResult uploadFileToOSS(File file, String folder) throws FileNotFoundException {

        return uploadFileToOSS(new FileInputStream(file), folder, file.getName());
    }


    /**
     * @param file
     * @param folder
     * @return
     * @方法名称 uploadFileToOSS
     * @功能描述 <pre>上传文件至oss</pre>
     */
    public static OSSObjectResult uploadFileToOSS(MultipartFile file, String folder, String fileName) throws IOException {

        return uploadFileToOSS(file.getInputStream(), folder, fileName);
    }


    /**
     * @param inputStream
     * @param folder
     * @return
     * @方法名称 uploadFileToOSS
     * @功能描述 <pre>上传文件至oss</pre>
     */
    public static OSSObjectResult uploadFileToOSS(InputStream inputStream, String folder, String fileName) {
        // 初始化OSSClient
        OSSClient ossClient = AliyunOSSClientUtil.getOSSClient();
        folder = createFolder(ossClient, BUCKET_NAME, folder);
        OSSObjectResult or = AliyunOSSClientUtil.uploadObject2OSS(ossClient, inputStream, BUCKET_NAME, folder, fileName);
        ossClient.shutdown();
        return or;
    }


    /**
     * @param key 包含目录 如 np/123.jpg
     * @方法名称 deleteFileToOSS
     * @功能描述 <pre>删除oss上的文件</pre>
     */
    public static void deleteFileToOSS(String folder, String key) {
        // 初始化OSSClient
        OSSClient ossClient = AliyunOSSClientUtil.getOSSClient();
        deleteFile(ossClient, BUCKET_NAME, folder + key);
        ossClient.shutdown();
    }

    /**
     * 获取阿里云OSS客户端对象
     *
     * @return ossClient
     */
    private static OSSClient getOSSClient() {
        return new OSSClient(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET);
    }

    /**
     * 创建模拟文件夹
     *
     * @param ossClient  oss连接
     * @param bucketName 存储空间
     * @param folder     模拟文件夹名如"qj_nanjing/"
     * @return 文件夹名
     */
    private static String createFolder(OSSClient ossClient, String bucketName, String folder) {
        // 文件夹名
        String keySuffixWithSlash = folder;
        // 判断文件夹是否存在，不存在则创建
        if (!ossClient.doesObjectExist(bucketName, keySuffixWithSlash)) {
            // 创建文件夹
            ossClient.putObject(bucketName, keySuffixWithSlash, new ByteArrayInputStream(new byte[0]));
            log.info("创建文件夹成功");
            // 得到文件夹名
            OSSObject object = ossClient.getObject(bucketName, keySuffixWithSlash);
            String fileDir = object.getKey();
            return fileDir;
        }
        return keySuffixWithSlash;
    }

    /**
     * 根据key删除OSS服务器上的文件
     *
     * @param ossClient  oss连接
     * @param bucketName 存储空间
     * @param key        Bucket下的文件的路径名+文件名 如："upload/cake.jpg"
     */
    private static void deleteFile(OSSClient ossClient, String bucketName, String key) {
        ossClient.deleteObject(bucketName, key);
        ossClient.shutdown();
        log.info("删除" + bucketName + "下的文件" + key + "成功");
    }


    /**
     * 上传图片至OSS
     *
     * @param ossClient  oss连接
     * @param is         上传文件（文件全路径如：D:\\image\\cake.jpg）
     * @param bucketName 存储空间
     * @param folder     模拟文件夹名 如"qj_nanjing/"
     * @return String 返回的唯一MD5数字签名
     */
    private static OSSObjectResult uploadObject2OSS(OSSClient ossClient, InputStream is, String bucketName, String folder, String fileName) {

        OSSObjectResult or = new OSSObjectResult();
        try {
            // 以输入流的形式上传文件
            //InputStream is = new ByteArrayInputStream(file.getBytes());
            // 文件名
            fileName = fileName;
            // 文件大小
            //Long fileSize = is
            // 创建上传Object的Metadata
            ObjectMetadata metadata = new ObjectMetadata();
            // 上传的文件的长度
            metadata.setContentLength(is.available());
            // 指定该Object被下载时的网页的缓存行为
            metadata.setCacheControl("no-cache");
            // 指定该Object下设置Header
            metadata.setHeader("Pragma", "no-cache");
            // 指定该Object被下载时的内容编码格式
            metadata.setContentEncoding("utf-8");
            // 文件的MIME，定义文件的类型及网页编码，决定浏览器将以什么形式、什么编码读取文件。如果用户没有指定则根据Key或文件名的扩展名生成，
            // 如果没有扩展名则填默认值application/octet-stream
            metadata.setContentType(getContentType(fileName));
            // 指定该Object被下载时的名称（指示MINME用户代理如何显示附加的文件，打开或下载，及文件名称）
            metadata.setContentDisposition("filename=" + fileName);
            // 上传文件 (上传文件流的形式)
            PutObjectResult putResult = ossClient.putObject(bucketName, folder + fileName, is, metadata);

            or.setPutObjectResult(putResult);
            int index = fileName.lastIndexOf(".");
            or.setFileName(fileName.substring(0, index));
            or.setSuffix(fileName.substring(index));
            or.setFileNameWidthSuffix(fileName);
            or.setFolder(folder);
            ossClient.shutdown();
            log.debug(putResult.toString());
        } catch (Exception e) {
            log.error("上传阿里云OSS服务器异常." + e.getMessage(), e);
        }
        return or;
    }

    /**
     * 通过文件名判断并获取OSS服务文件上传时文件的contentType
     *
     * @param fileName 文件名
     * @return 文件的contentType
     */
    private static String getContentType(String fileName) {
        // 文件的后缀名
        String fileExtension = fileName.substring(fileName.lastIndexOf("."));
        if (".bmp".equalsIgnoreCase(fileExtension)) {
            return "image/bmp";
        }
        if (".gif".equalsIgnoreCase(fileExtension)) {
            return "image/gif";
        }
        if (".jpeg".equalsIgnoreCase(fileExtension) || ".jpg".equalsIgnoreCase(fileExtension)
                || ".png".equalsIgnoreCase(fileExtension)) {
            return "image/jpeg";
        }
        if (".html".equalsIgnoreCase(fileExtension)) {
            return "text/html";
        }
        if (".txt".equalsIgnoreCase(fileExtension)) {
            return "text/plain";
        }
        if (".vsd".equalsIgnoreCase(fileExtension)) {
            return "application/vnd.visio";
        }
        if (".ppt".equalsIgnoreCase(fileExtension) || "pptx".equalsIgnoreCase(fileExtension)) {
            return "application/vnd.ms-powerpoint";
        }
        if (".doc".equalsIgnoreCase(fileExtension) || "docx".equalsIgnoreCase(fileExtension)) {
            return "application/msword";
        }
        if (".xml".equalsIgnoreCase(fileExtension)) {
            return "text/xml";
        }
        if (".jpeg".equalsIgnoreCase(fileExtension) || ".jpg".equalsIgnoreCase(fileExtension)
                || ".png".equalsIgnoreCase(fileExtension)) {
            return "image/jpeg";
        }

        //视频格式
        if (".mp4".equalsIgnoreCase(fileExtension)) {
            return "video/mpeg4";
        }
        if (".wmv".equalsIgnoreCase(fileExtension)) {
            return "video/x-ms-wmv";
        }
        if (".rv".equalsIgnoreCase(fileExtension)) {
            return "video/vnd.rn-realvideo";
        }
        if (".flv".equalsIgnoreCase(fileExtension)) {
            return "video/x-flv";
        }
        if (".m2v".equalsIgnoreCase(fileExtension)) {
            return "video/x-mpeg";
        }
        if (".m4e".equalsIgnoreCase(fileExtension)) {
            return "video/mpeg4";
        }
        if (".mp2v".equalsIgnoreCase(fileExtension)) {
            return "video/mpeg";
        }
        if (".mpv".equalsIgnoreCase(fileExtension)) {
            return "video/mpg";
        }
        if (".mps".equalsIgnoreCase(fileExtension)) {
            return "video/x-mpeg";
        }
        if (".mpeg".equalsIgnoreCase(fileExtension)) {
            return "video/mpg";
        }
        // 默认返回类型
        return "image/jpeg";
    }

    public static void main(String[] args) {
//		AliyunOSSClientUtil.deleteFileToOSS(CommonDataConst.CLASS_ACTIVITY_IMG,"402880f56362c50f016362c50fd20000.jpg");
    }


    /**
     * @param dir
     * @return
     */
    public static Map<String, String> uploadFile(MultipartFile file, String dir, String fileName) {
        OSSObjectResult os = null;
        try {
            os = AliyunOSSClientUtil.uploadFileToOSS(file, dir, fileName);
        } catch (IOException e) {
            e.printStackTrace();
        }
        Map<String, String> map = new HashMap<>();

        map.put("filePath", dir + os.getFileNameWidthSuffix());
        return map;
    }

}
